package com.lxw.camera.presenter

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.graphics.Point
import android.hardware.camera2.*
import android.media.Image
import android.media.ImageReader
import android.os.Build
import android.os.Handler
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.lxw.camera.ui.activity.MainActivity
import com.lxw.camera.util.CompareSizesByArea
import com.lxw.camera.util.LargestUtil
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*


/**
 * 猿代码： Lxw
 * Email: China2021@126.com
 * 时间轴： 2018年 03月 08 日 下午5:26
 */
class MainPresenter : BasePresenter<MainActivity>() {
    private val TAG = "MainPresenter"
    private var available = false
    private var mCameraDevice: CameraDevice? = null
    private var mCaptureRequestBuilder: CaptureRequest.Builder? = null
    private var mSurfaceHolder: SurfaceHolder? = null
    private var mCameraCaptureSession: CameraCaptureSession? = null
    private var mCaptureRequest: CaptureRequest? = null
    private var mState = STATE_WAITING_LOCK
    private var mSensorOrientation: Int? = null
    private var mImageReader: ImageReader? = null

    private val mBackgroundHandler = Handler {

        Log.d(TAG, "收到信息：arg1 = ${it.arg1}, arg2 = ${it.arg2}, what = ${it.what})")
        false
    }

    fun openCamera(context: Context, activity: Activity) {
        if (checkCameraPermission(context, activity)) {
            val availableCameraId = getAvailableCameraId(context)
            if (availableCameraId != null) {
                connectCamera(context, availableCameraId)
            }
        }
    }


    /**
     * 检测相机权限。
     */
    private fun checkCameraPermission(context: Context, activity: Activity): Boolean {
        //检测权限，片段是否授权。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //如果未获得权限
            return if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //如果之前拒绝过权限，应该给予友好提示,并再次申请权限
                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {
                    getView()?.showToastMessage("我们需要您的授权才能继续工作 请在设置权限中开启权限")
                    ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), MainPresenter.OPEN_CAMERA)
                    false
                } else {
                    //申请权限
                    ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), MainPresenter.OPEN_CAMERA)
                    false
                }
            } else {
                getView()?.showToastMessage("直接就有权限了！！！")
                true
            }
        } else {
            return true
        }
    }


    /**
     * 获取可用摄像头的Id
     * [context]：上下文
     */
    private fun getAvailableCameraId(context: Context): String? {
        val mCameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        var id: String? = null
        for (cameraId in mCameraManager.cameraIdList) {
            val mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId)
            val facing = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
            if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                continue
            }
            mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                    ?: continue
            available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
            id = cameraId
        }
        return id

    }


    /**
     * 链接指定的摄像头：
     * [context]：上下文
     * [cameraId]：摄像头id
     */
    @SuppressLint("MissingPermission")
    private fun connectCamera(context: Context, cameraId: String) {
        val mCameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        mCameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
            override fun onOpened(camera: CameraDevice?) {
                mCameraDevice = camera
                //创建预览会话Session
                createCameraPreviewSession()
            }

            override fun onDisconnected(camera: CameraDevice?) {

            }

            override fun onError(camera: CameraDevice?, error: Int) {
            }

        }, Handler())
    }


    /**
     * 链接摄像头成功之后，创建一个会话和摄像头进行通讯
     */
    private fun createCameraPreviewSession() {
        mSurfaceHolder = getView()?.getSurfaceView()?.holder
        mCaptureRequestBuilder = mCameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        mCaptureRequestBuilder?.addTarget(mSurfaceHolder?.surface)

        mCameraDevice?.createCaptureSession(listOf(mSurfaceHolder?.surface), object : CameraCaptureSession.StateCallback() {


            override fun onConfigured(session: CameraCaptureSession?) {
                if (mCameraDevice == null) {
                    return
                }
                mCameraCaptureSession = session

                //设置自动对焦
                mCaptureRequestBuilder?.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)

                mCaptureRequestBuilder?.let { setAutoFlash(it) }


                mCaptureRequest = mCaptureRequestBuilder?.build()
                mCameraCaptureSession?.setRepeatingRequest(mCaptureRequest, mCaptureCallBack, mBackgroundHandler)
            }

            override fun onConfigureFailed(session: CameraCaptureSession?) {
                Log.d(TAG, "开启预览失败")
            }

        }, null)
    }


    /**
     * 对焦
     */
    private fun lockFocus() {
        mCaptureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)
        mState = STATE_WAITING_LOCK
        mCameraCaptureSession?.capture(mCaptureRequestBuilder?.build(), mCaptureCallBack, mBackgroundHandler)
    }


    /**
     * 对焦回调
     */
    private val mCaptureCallBack = object : CameraCaptureSession.CaptureCallback() {

        private fun process(result: CaptureResult) {
            when (mState) {
                STATE_PREVIEW -> {
                    Log.d(TAG, "预览状态")
                }

                STATE_WAITING_LOCK -> {
                    Log.d(TAG, "等待对焦")
                    val afState = result.get(CaptureResult.CONTROL_AF_STATE)
                    when (afState) {
                        null -> {
                            captureStillPicture()
                        }

                        CaptureRequest.CONTROL_AF_STATE_FOCUSED_LOCKED, CaptureRequest.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED -> {
                            val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
                            when (aeState) {
                                null, CaptureRequest.CONTROL_AE_STATE_CONVERGED -> {
                                    mState = STATE_PICTURE_TAKEN
                                    captureStillPicture()
                                }
                                else -> {
                                    runPreCaptureSequence()
                                }
                            }
                        }
                    }
                }

                STATE_WAITING_PRE_CAPTURE -> {
                    val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
                    when (aeState) {
                        null, CaptureResult.CONTROL_AE_STATE_PRECAPTURE, CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED -> {
                            mState = STATE_WAITING_NON_PRE_CAPTURE
                        }
                    }
                }

                STATE_WAITING_NON_PRE_CAPTURE -> {
                    val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                        mState = STATE_PICTURE_TAKEN
                        captureStillPicture()
                    }
                }
            }
        }

        override fun onCaptureProgressed(session: CameraCaptureSession?, request: CaptureRequest?, partialResult: CaptureResult?) {
            if (partialResult != null) {
                process(partialResult)
            }
        }

        override fun onCaptureCompleted(session: CameraCaptureSession?, request: CaptureRequest?, result: TotalCaptureResult?) {
            if (result != null) {
                process(result)
            }
        }

    }

    /**
     * 捕获静态图像的预捕获序列
     */
    private fun runPreCaptureSequence() {
        mCaptureRequestBuilder?.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START)
        mState = STATE_WAITING_PRE_CAPTURE
        mCameraCaptureSession?.capture(mCaptureRequestBuilder?.build(), mCaptureCallBack, mBackgroundHandler)
    }


    /**
     * 拍摄静态图片
     */
    private fun captureStillPicture() {
        //要获取Activity?
        val mActivity = getView()?.getActivity()
        if (mCameraDevice == null) {
            return
        }

        val mCameraDevice = mCameraDevice!!

        val mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
        mCaptureRequestBuilder.addTarget(mImageReader?.surface)
        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
        mCaptureRequestBuilder.let { setAutoFlash(it) }

        val rotation = getView()?.windowManager?.defaultDisplay?.rotation
        mCaptureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotation)

        val mCameraCaptureSessionCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
            override fun onCaptureCompleted(session: CameraCaptureSession?, request: CaptureRequest?, result: TotalCaptureResult?) {
                getView()?.showToastMessage("save: + ${getView()?.getPicFile()}")
                Log.d(TAG, getView()?.getPicFile().toString())
            }
        }

        mCameraCaptureSession?.stopRepeating()

        Log.i(TAG, "相机准备就绪，开始捕获图片")
        mCameraCaptureSession?.capture(mCaptureRequestBuilder.build(), mCameraCaptureSessionCaptureCallback, null)

    }


    /**
     * 设置相机参数
     */
    private fun setUpCameraOutputs(width: Int, height: Int) {
        val mActivity = getView()?.getActivity()
        var mCameraManager = mActivity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager

        for (cameraId in mCameraManager.cameraIdList) {
            val mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId)
            val facing = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
            if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                continue
            }

            val map = mCameraCharacteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue

            //使用最大可用尺寸
            val largest = LargestUtil.getLargestSize(map)
            mImageReader = ImageReader.newInstance(largest.width, largest.height, ImageFormat.JPEG, 2)

            mImageReader?.setOnImageAvailableListener({
                Log.d(TAG, "创建图片")
                val mFile = getView()?.getPicFile()
                if (mFile != null) {
                    mBackgroundHandler.post(ImageSaver(it.acquireNextImage(), mFile))
                }
            }, mBackgroundHandler)


            val displayRotation = getView()?.getActivity()?.windowManager?.defaultDisplay?.rotation


            mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)

            var swappeDimensions = false
            when (displayRotation) {
                Surface.ROTATION_0, Surface.ROTATION_180 -> {
                    if (mSensorOrientation == 90 || mSensorOrientation == 270) {
                        swappeDimensions = true
                    }
                }
                Surface.ROTATION_90, Surface.ROTATION_270 -> {
                    if (mSensorOrientation == 0 || mSensorOrientation == 180) {
                        swappeDimensions = true
                    }
                }
                else -> {
                    Log.e(TAG, "Display rotation is invalid")
                }
            }

            val mPoint = Point()

            getView()?.getActivity()?.windowManager?.defaultDisplay?.getSize(mPoint)

            var rotatedPreviewWidth = width
            var rotatedPreviewHeight = height
            var maxPreviewWidth = mPoint.x
            var maxPreviewHeight = mPoint.y

            if (swappeDimensions) {
                rotatedPreviewWidth = height
                rotatedPreviewHeight = width
                maxPreviewWidth = mPoint.y
                maxPreviewHeight = mPoint.x
            }

            if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                maxPreviewHeight = MAX_PREVIEW_HEIGHT
            }

            if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                maxPreviewWidth = MAX_PREVIEW_WIDTH
            }

            var mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceView::class.java), width, rotatedPreviewHeight, rotatedPreviewWidth, maxPreviewHeight, largest)

        }
    }


    fun chooseOptimalSize(choices: Array<Size>, textureViewWidth: Int,
                          textureViewHeight: Int, maxWidth: Int, maxHeight: Int, aspectRatio: Size): Size {

        // Collect the supported resolutions that are at least as big as the preview Surface
        val bigEnough = ArrayList<Size>()
        // Collect the supported resolutions that are smaller than the preview Surface
        val notBigEnough = ArrayList<Size>()
        val w = aspectRatio.width
        val h = aspectRatio.height

        for (item in choices) {
            if (item.width <= maxWidth && item.height <= maxHeight &&
                    item.height == item.width * h / w) {
                if (item.width >= textureViewWidth &&
                        item.height >= textureViewHeight) {
                    bigEnough.add(item)
                } else {
                    notBigEnough.add(item)
                }
            }
        }
        return when {
            bigEnough.size > 0 -> Collections.min(bigEnough, CompareSizesByArea())
            notBigEnough.size > 0 -> Collections.max(notBigEnough, CompareSizesByArea())
            else -> {
                Log.e(TAG, "Couldn't find any suitable preview size")
                choices[0]
            }
        }
    }


    /**
     * 处理图片保存类
     */
    open class ImageSaver(var image: Image, var file: File) : Runnable {
        override fun run() {
            val mByteBuffer = image.planes[0].buffer
            val mByteArray = ByteArray(mByteBuffer.remaining())

            var fos: FileOutputStream? = null
            try {
                fos = FileOutputStream(file)
                fos.write(mByteArray)
                Log.d(TAG, "文件处理完毕")
            } catch (e: IOException) {
                Log.d(TAG, "处理图片出现问题")
            } finally {
                image.close()
                fos?.close()
                Log.d(TAG, "释放资源")
            }
        }
    }


    fun setAutoFlash(requestBuilder: CaptureRequest.Builder) {
        if (available) {
            requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
        }
    }


    /**
     * 常量
     */
    companion object {
        /** 打开相机请求码*/
        const val OPEN_CAMERA = 1
        /** 相机状态——预览*/
        const val STATE_PREVIEW = 2
        /** 相机状态——等待对角*/
        const val STATE_WAITING_LOCK = 3
        /** 相机状态——对焦完成（准备捕获照片）*/
        const val STATE_PICTURE_TAKEN = 4
        /** 相机状态——预捕获*/
        const val STATE_WAITING_PRE_CAPTURE = 5
        /** 等待曝光*/
        const val STATE_WAITING_NON_PRE_CAPTURE = 6

        /** Log日志标记*/
        const val TAG = "MainPresenter"

        /** 最大预览宽度*/
        const val MAX_PREVIEW_WIDTH = 1920
        /** */
        const val MAX_PREVIEW_HEIGHT = 1080

    }


    /**
     * 释放相机资源
     */
    fun releaseCameraDevice() {
        Log.d(TAG, "开始释放相机")
        mCameraDevice?.close()
        mCameraDevice = null
        mCameraCaptureSession = null
        mCaptureRequestBuilder = null
        mCaptureRequestBuilder = null

        Log.d(TAG, "完成释放相机")
    }

}